using AutoMapper;
using B.S.Medical.Api.Write.Application.Command.Register;
using B.S.Medical.Domain.Department;
using B.S.Medical.Domain.Doctor;
using B.S.Medical.Domain.Medical;
using B.S.Medical.Domain.Payment;
using B.S.Medical.ErrorCode;
using B.S.Medical.Infrastructure.Interface;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace B.S.Medical.Api.Write.Application.Handler.Register
{
    /// <summary>
    /// 添加挂号记录处理器
    /// </summary>
    public class AddRegisterHandler : IRequestHandler<AddRegisterCommand, ApiResult<int>>
    {
        private readonly IBaseRepository<RegisterModel> _registerRepository;
        private readonly IBaseRepository<DoctorScheduleModel> _scheduleRepository;
        private readonly IBaseRepository<registrationModel> _registrationRepository;
        private readonly IBaseRepository<PatientModel> _patientRepository;
        private readonly IBaseRepository<DoctorModel> _doctorRepository;
        private readonly IBaseRepository<ManageModel> _departmentRepository;
        private readonly IBaseRepository<PaymentRecordModel> _paymentRecordRepository;
        private readonly IBaseRepository<PatientBalance> _patientBalanceRepository;
        private readonly IMapper _mapper;
        private readonly ILogger<AddRegisterHandler> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        public AddRegisterHandler(
            IBaseRepository<RegisterModel> registerRepository,
            IBaseRepository<DoctorScheduleModel> scheduleRepository,
            IBaseRepository<registrationModel> registrationRepository,
            IBaseRepository<PatientModel> patientRepository,
            IBaseRepository<DoctorModel> doctorRepository,
            IBaseRepository<ManageModel> departmentRepository,
            IBaseRepository<PaymentRecordModel> paymentRecordRepository,
            IBaseRepository<PatientBalance> patientBalanceRepository,
            IMapper mapper,
            ILogger<AddRegisterHandler> logger)
        {
            _registerRepository = registerRepository;
            _scheduleRepository = scheduleRepository;
            _registrationRepository = registrationRepository;
            _patientRepository = patientRepository;
            _doctorRepository = doctorRepository;
            _departmentRepository = departmentRepository;
            _paymentRecordRepository = paymentRecordRepository;
            _patientBalanceRepository = patientBalanceRepository;
            _mapper = mapper;
            _logger = logger;
        }

        /// <summary>
        /// 处理添加挂号记录请求
        /// </summary>
        public async Task<ApiResult<int>> Handle(AddRegisterCommand request, CancellationToken cancellationToken)
        {
            ApiResult<int> res = new ApiResult<int>();
            try
            {
                // 验证患者存在
                var patient = await _patientRepository.GetValue(request.PatientId);
                if (patient == null)
                {
                    res.Msg = "患者信息不存在";
                    res.Code = ApiEnum.Fail;
                    return res;
                }

                // 查询患者余额
                var patientBalance = await _patientBalanceRepository.GetAll()
                    .FirstOrDefaultAsync(p => p.PatientId == request.PatientId && !p.IsDeleted);
                
                if (patientBalance == null)
                {
                    res.Msg = "患者余额信息不存在";
                    res.Code = ApiEnum.Fail;
                    return res;
                }

                // 检查余额是否足够
                if (patientBalance.Balance < request.Fee)
                {
                    res.Msg = "患者余额不足，请先充值";
                    res.Code = ApiEnum.Fail;
                    return res;
                }

                // 验证医生存在
                var doctor = await _doctorRepository.GetValue(request.DoctorId);
                if (doctor == null)
                {
                    res.Msg = "医生信息不存在";
                    res.Code = ApiEnum.Fail;
                    return res;
                }

                // 验证科室存在
                var department = await _departmentRepository.GetValue(request.DepartmentId);
                if (department == null)
                {
                    res.Msg = "科室信息不存在";
                    res.Code = ApiEnum.Fail;
                    return res;
                }

                // 查询排班信息，验证号源是否足够
                var schedule = await _scheduleRepository.GetValue((int)request.Schedule_id);
                if (schedule == null)
                {
                    res.Msg = "排班信息不存在";
                    res.Code = ApiEnum.Fail;
                    return res;
                }

                // 查询该医生该日期已预约的数量
                var appointedCount = _registerRepository.GetAll()
                    .Count(r => !r.IsDeleted && 
                           r.DoctorId == request.DoctorId && 
                           r.VisitDate.Date == request.VisitDate.Date &&
                           r.Schedule_id == request.Schedule_id);

                // 判断号源是否足够
                if (appointedCount >= schedule.SlotCount)
                {
                    res.Msg = "该医生号源已满，请选择其他医生或时间";
                    res.Code = ApiEnum.Fail;
                    return res;
                }

                // 查询可用号源
                var availableSlot = await _registrationRepository.GetAll()
                    .Where(r => !r.IsDeleted && 
                           r.schedule_id == request.Schedule_id && 
                           (r.status == 0)) // 0表示未预约
                    .FirstOrDefaultAsync();

                if (availableSlot == null)
                {
                    res.Msg = "没有可用号源";
                    res.Code = ApiEnum.Fail;
                    return res;
                }

                // 设置号源为已预约
                availableSlot.status = 1; // 1表示已预约
              
                await _registrationRepository.UpdateAsync(availableSlot);

                // 创建挂号记录 
                var register = new RegisterModel
                {
                    // 基本关联信息
                    PatientId = request.PatientId,
                    DoctorId = request.DoctorId,
                    Schedule_id = request.Schedule_id,
                    registrationId = availableSlot.Id,
                    
                    // 基本挂号信息
                    Type = request.Type,
                    Fee = request.Fee,
                    VisitDate = request.VisitDate,
                    AppointmentTime = request.AppointmentTime,
                    RegisterRemark = request.RegisterRemark,
                    
                    // 设置默认字段
                    IsDeleted = false,
                    Status = "待就诊",
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now,
                    slot_number = appointedCount + 1,
                    Reservecause = "暂无", // 设置取消原因为"暂无"
                    Reservetime = DateTime.Now.AddDays(5), // 设置取消时间为5天后
                    WaitTime = request.WaitTime ?? "" // 使用请求中的候诊时间，如果为空则设置为空字符串
                };

                // 保存到数据库
                var result = await _registerRepository.CreateAsync(register);
                if (result > 0)
                {
                    // 挂号成功，扣减患者余额
                    patientBalance.Balance -= request.Fee;
                    patientBalance.UpdateTime = DateTime.Now;
                    patientBalance.LastUpdatedTime = DateTime.Now;
                    patientBalance.Remark = $"挂号费用支付：{request.Fee}元";
                    
                    var balanceUpdateResult = await _patientBalanceRepository.UpdateAsync(patientBalance);
                    if (balanceUpdateResult <= 0)
                    {
                        // 余额更新失败，回滚挂号记录
                        // await _registerRepository.DeleteAsync(result);
                        // 使用软删除代替物理删除
                        var registerToDelete = await _registerRepository.GetValue(result);
                        if (registerToDelete != null)
                        {
                            registerToDelete.IsDeleted = true;
                            await _registerRepository.UpdateAsync(registerToDelete);
                        }
                        
                        // 恢复号源状态
                        availableSlot.status = 0;
                        await _registrationRepository.UpdateAsync(availableSlot);
                        
                        res.Msg = "扣减余额失败，挂号已取消";
                        res.Code = ApiEnum.Fail;
                        _logger.LogError($"扣减患者余额失败，患者ID: {request.PatientId}，挂号记录ID: {result}");
                        return res;
                    }
                    
                    // 创建支付记录
                    try
                    {
                        // 生成订单号
                        string orderNo = $"REG{DateTime.Now:yyyyMMddHHmmss}{request.PatientId}";
                        
                        // 创建支付记录
                        var paymentRecord = new PaymentRecordModel
                        {
                            PatientId = request.PatientId,
                            DoctorId = request.DoctorId,
                            ItemName = "挂号费", // 项目名称设为挂号费
                            Amount = request.Fee, // 金额为挂号费
                            IsPaid = false, // 设置为未支付
                            CreatedTime = DateTime.Now,
                            OrderNo = orderNo,
                            PayAmount = request.Fee,
                            PayStatus = "待支付", // 设置支付状态为待支付
                            CreateTime = DateTime.Now,
                            UpdateTime = DateTime.Now
                        };
                        
                        // 保存支付记录
                        await _paymentRecordRepository.CreateAsync(paymentRecord);
                        _logger.LogInformation($"创建挂号费支付记录成功，患者ID: {request.PatientId}，医生ID: {request.DoctorId}，挂号记录ID: {result}，订单号: {orderNo}");
                    }
                    catch (Exception ex)
                    {
                        // 支付记录创建失败，但不影响挂号结果
                        _logger.LogError(ex, $"创建挂号费支付记录失败，患者ID: {request.PatientId}，医生ID: {request.DoctorId}，挂号记录ID: {result}");
                    }
                    
                    res.Msg = "挂号成功";
                    res.Code = ApiEnum.Success;
                    res.Data = result;
                    _logger.LogInformation($"添加挂号记录成功，ID: {result}，患者ID: {request.PatientId}，医生ID: {request.DoctorId}，号源ID: {availableSlot.Id}，已从患者余额扣除：{request.Fee}");
                }
                else
                {
                    // 如果挂号失败，恢复号源状态
                    availableSlot.status = 0;
                    await _registrationRepository.UpdateAsync(availableSlot);
                    
                    res.Msg = "挂号失败";
                    res.Code = ApiEnum.Fail;
                    _logger.LogError($"添加挂号记录失败，患者ID: {request.PatientId}，医生ID: {request.DoctorId}");
                }

                return res;
            }
            catch (Exception ex)
            {
                res.Msg = "挂号过程中发生异常: " + ex.Message;
                res.Code = ApiEnum.Error;
                _logger.LogError(ex, $"添加挂号记录异常，患者ID: {request.PatientId}，医生ID: {request.DoctorId}");
                return res;
            }
        }
    }
} 